import type { PatchState, Transaction } from "@rivet/state";
import type { Editor } from "./editor.ts";
import type { AnyCommands, CommandProps, SingleCommands } from "./types.ts";
import { createChainableState } from "./helpers/createChainableState.ts";
export class CommandManager {
  editor: Editor;

  rawCommands: AnyCommands;

  customState?: PatchState;
  constructor(props: {
    editor: Editor;
    state?: PatchState;
  }) {
    this.editor = props.editor;
    this.rawCommands = this.editor.extensionManager.commands;
    this.customState = props.state;
  }
  get hasCustomState(): boolean {
    return !!this.customState;
  }
  get state(): PatchState {
    return this.customState || this.editor.state;
  }
  get commands(): SingleCommands {
    const { rawCommands, editor, state } = this;

    const { tr } = state;
    const props = this.buildProps(tr);

    return Object.fromEntries(
      Object
        .entries(rawCommands)
        .map(([name, command]) => {
          const method = (...args: any[]) => {
            const callback = command(...args)(props);
            if (!tr.getMeta("preventDispatch") && !this.hasCustomState) {
              editor.dispatch(tr);
            }
            return callback;
          };

          return [name, method];
        }),
    ) as unknown as SingleCommands;
  }
  public buildProps(tr: Transaction): CommandProps {
    const { editor, state } = this;

    const props: CommandProps = {
      tr,
      editor,
      state: createChainableState({
        state,
        transaction: tr,
      }),
    };

    return props;
  }
}
